﻿using CyUSB;
using debugger;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public class Base : Form
    {
        void usbDevices_DeviceRemoved(object sender, EventArgs e)
        {
            setDevice();
        }
        void usbDevices_DeviceAttached(object sender, EventArgs e)
        {
            setDevice();
        }
        public bool isBasic;
        public void setDevice()
        {
            loopDevice = usbDevices[0x04b4, 0x1004] as CyUSBDevice;
            CyFX2Device progDevice = usbDevices[0x04b4, 0x8613] as CyFX2Device;
            if (loopDevice == null && progDevice != null)
            {
                //progDevice.LoadExternalRam(@"D:\MyCode.github\cy7c68013a\Bulkloop.firm.my\bulkloop.hex");
                //progDevice.LoadExternalRam(@"D:\MyCode.github\cy7c68013a\test1004slavefifo\bulkloop.hex");
                //progDevice.LoadExternalRam(@"debugger.cy7c68013a\cy7c68013a_slavefifo_firmwarepio\bulkloop.hex");
                progDevice.LoadExternalRam(@"bulkloop.hex");
            }

            if (loopDevice != null)
            {
                this.Text = loopDevice.FriendlyName;
                //EndpointAddress 8:in from cy  0:out to cy
                outCmdEndpoint = loopDevice.EndPointOf(0x01) as CyBulkEndPoint;
                inCmdEndpoint = loopDevice.EndPointOf(0x81) as CyBulkEndPoint;
                outEndpoint = loopDevice.EndPointOf(0x02) as CyBulkEndPoint;
                inEndpoint = loopDevice.EndPointOf(0x86) as CyBulkEndPoint;
                if (outEndpoint.MaxPktSize != 512)
                {
                    MessageBox.Show("MaxPktSize != 512");
                }
                outEndpoint.TimeOut = 100;
                inEndpoint.TimeOut = 100;
                outCmdEndpoint.TimeOut = 100;
                inCmdEndpoint.TimeOut = 100;

                outEndpoint.Abort();
                inEndpoint.Abort();
                outCmdEndpoint.Abort();
                inCmdEndpoint.Abort();

                outEndpoint.Reset();
                inEndpoint.Reset();
                outCmdEndpoint.Reset();
                inCmdEndpoint.Reset();

                Thread.Sleep(10);
                try
                {
                    uint temp = sendCmdRet(0x01, 123);
                    isBasic = (temp & 0x10) != 0;
                    temp = temp & 0x0F;
                    if (temp != 0x0A)
                    {
                        this.Text = "ERROR";
                        Application.Exit();
                    }
                }
                catch (Exception ex) {
                    this.Text = "Exception";
                }

            }
            else
            {
                this.Text = "Bulkloop - no device";
            }
        }

        USBDeviceList usbDevices = null;
        CyUSBDevice loopDevice = null;
        CyBulkEndPoint inEndpoint = null;
        CyBulkEndPoint outEndpoint = null;
        CyBulkEndPoint inCmdEndpoint = null;
        CyBulkEndPoint outCmdEndpoint = null;

        public bool connect()
        {
            // Create a list of CYUSB devices
            usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

            //Adding event handlers for device attachment and device removal
            usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
            usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);

            //The below function sets the device with particular VID and PId and searches for the device with the same VID and PID.
            setDevice();
            return true;
        }
        private uint readFromPort()
        {
            int size = 4;
            bool bResult;
            byte[] inData = new byte[4];
            Stopwatch sw = new Stopwatch();
            sw.Start();
            while (true)
            {
                int xferLen = size;
                bResult = inCmdEndpoint.XferData(ref inData, ref xferLen);
                if (bResult)
                {
                    break;
                }
                if (sw.ElapsedMilliseconds > 1000)
                {
                    throw new Exception();
                }
            }
            uint ret = 0;
            ret |= (uint)inData[0] << 0;
            ret |= (uint)inData[1] << 8;
            ret |= (uint)inData[2] << 16;
            ret |= (uint)inData[3] << 24;
            return ret;
        }

        public uint sendCmdRet(byte cmd, uint? udata = null)
        {
            return sendCmd(cmd, udata);
        }

        public uint sendCmd(byte cmd, uint? udata = null)
        {
            int size = 5;
            bool bResult;
            byte[] outData = new byte[5];
            outData[0] = (byte)cmd;
            if (udata == null)
            {
                udata = 0;
            }
            outData[1] = (byte)(udata >> 0);
            outData[2] = (byte)(udata >> 8);
            outData[3] = (byte)(udata >> 16);
            outData[4] = (byte)(udata >> 24);
            int xferLen = size;
            bResult = outCmdEndpoint.XferData(ref outData, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
            uint val = 0;
            val = readFromPort();
            return val;
        }


        public void sendCmdNoRes(byte cmd, uint? udata = null)
        {
            int size = 5;
            bool bResult;
            byte[] outData = new byte[5];
            outData[0] = (byte)cmd;
            if (udata == null)
            {
                udata = 0;
            }
            outData[1] = (byte)(udata >> 0);
            outData[2] = (byte)(udata >> 8);
            outData[3] = (byte)(udata >> 16);
            outData[4] = (byte)(udata >> 24);
            int xferLen = size;
            bResult = outCmdEndpoint.XferData(ref outData, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
        }
        static readonly int PAGESIZE = 1024;

        bool is8bit = false;
        uint channel = 0;
        uint receive_phase = 0 << 3;
        uint send_phase = 1 << 3;

        //public void receive(byte[] data)//read
        //{
        //    sendCmd(0x04, receive_phase | 6);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b110
        //    if (data.Length != 2048)
        //    {
        //        throw new Exception();
        //    }
        //    if (is8bit)
        //    {
        //        uint ack;
        //        bool bResult;
        //        int xferLen;
        //        for (uint j = 0; j < 4; j++)
        //        {
        //            ack = sendCmd(0x03, j);
        //            xferLen = PAGESIZE;
        //            bResult = inEndpoint.XferData(ref data2, ref xferLen);
        //            if (!bResult)
        //            {
        //                throw new Exception();
        //            }
        //            for (int i = 0; i < 512; i++)
        //            {
        //                data[i + j * 512] = data2[i * 2 + channel];
        //            }
        //        }
        //    }
        //    else
        //    {
        //        uint ack;
        //        ack = sendCmd(0x03, 0);
        //
        //        bool bResult;
        //
        //        int xferLen;
        //
        //        xferLen = PAGESIZE;
        //        bResult = inEndpoint.XferData(ref data, ref xferLen);
        //        if (!bResult)
        //        {
        //            throw new Exception();
        //        }
        //
        //        ack = sendCmd(0x03, 1);
        //
        //        xferLen = PAGESIZE;
        //        bResult = inEndpoint.XferData(ref data2, ref xferLen);
        //        if (!bResult)
        //        {
        //            throw new Exception();
        //        }
        //        for (int i = 0; i < 1024; i++)
        //        {
        //            data[i + 1024] = data2[i];
        //        }
        //    }
        //    sendCmd(0x04, receive_phase | 2);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b010
        //}
        public void receive1024(byte[] data)//read
        {
            sendCmd(0x04, receive_phase | 6);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b110
            if (data.Length != 1024)
            {
                throw new Exception();
            }
            uint ack;
            ack = sendCmd(0x03, 0);

            bool bResult;

            int xferLen;

            xferLen = PAGESIZE;
            bResult = inEndpoint.XferData(ref data, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
            
            sendCmd(0x04, receive_phase | 2);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b010
        }

        //public void send(byte[] data)//write
        //{
        //    sendCmd(0x04, send_phase | 5);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b101
        //    uint ack;
        //    int xferLen;
        //    bool bResult;
        //
        //    if (data.Length != 2048)
        //    {
        //        throw new Exception();
        //    }
        //    if (is8bit)
        //    {
        //        for (uint j = 0; j < 4; j++)
        //        {
        //            for (int i = 0; i < 512; i++)
        //            {
        //                data2[i * 2 + channel] = data[i + j * 512];
        //            }
        //
        //            xferLen = PAGESIZE;
        //            bResult = outEndpoint.XferData(ref data2, ref xferLen);
        //            if (!bResult)
        //            {
        //                throw new Exception();
        //            }
        //
        //            ack = sendCmd(0x02, j);
        //        }
        //    }
        //    else
        //    {
        //        xferLen = PAGESIZE;
        //        bResult = outEndpoint.XferData(ref data, ref xferLen);
        //        if (!bResult)
        //        {
        //            throw new Exception();
        //        }
        //
        //        ack = sendCmdRet(0x02, 0);
        //
        //        for (int i = 0; i < 1024; i++)
        //        {
        //            data2[i] = data[i + 1024];
        //        }
        //
        //        xferLen = PAGESIZE;
        //        bResult = outEndpoint.XferData(ref data2, ref xferLen);
        //        if (!bResult)
        //        {
        //            throw new Exception();
        //        }
        //
        //
        //        ack = sendCmd(0x02, 1);
        //    }
        //
        //    sendCmd(0x04, send_phase | 3);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b011
        //
        //}

        public void send1024(byte[] data)//write
        {
            sendCmd(0x04, send_phase | 5);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b101
            uint ack;
            int xferLen;
            bool bResult;

            if (data.Length != 1024)
            {
                throw new Exception();
            }

            xferLen = PAGESIZE;
            bResult = outEndpoint.XferData(ref data, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }

            ack = sendCmdRet(0x02, 0);

            sendCmd(0x04, send_phase | 3);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b011

        }

        byte[] data2 = new byte[1024];

        public bool fast = true;
        public void getVGA(byte[] data, uint pos)//read
        {
            sendCmd(0x04, receive_phase | 6);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b110

            sendCmdNoRes(0x05, pos);

            bool bResult;

            int xferLen;
            for (int j = 0; j < 768 * 2; j++)
            {
                xferLen = PAGESIZE;
                bResult = inEndpoint.XferData(ref data2, ref xferLen);
                if (!bResult)
                {
                    throw new Exception();
                }
                for (int i = 0; i < 1024; i++)
                {
                    data[i + j * 1024] = data2[i];
                }
            }

            uint val = 0;
            val = readFromPort();

            sendCmd(0x04, receive_phase | 2);//{control_by_transfer,cy_from_fpga_A2_SLOE,transfer_type} <= 3'b010
        }

    }
}
